﻿using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// This is the delegate for the even more advanced pixel delegate
    /// </summary>
    /// <param name="pixel"></param>
    /// <returns></returns>
    public delegate Color GreaterPixelDelegate(LambdaPixel pixel); 

    /// <summary>
    /// I guess this needs an example:
    /// use it for example like this:
    /// 
    ///     //FlipPixels
    ///        new GreaterLambdaCommand().Apply(_bitmap, delegate (LambdaPixel p) {
    ///        return p.SourceImage.GetPixel(p.X, (p.Area.Bottom - p.Y) - 1);
    ///    });
    /// </summary>
    public class GreaterLambdaCommand : LambdaCommand
    {
        /// <summary>
        /// This is the extended delegate for the "GreaterLambdaCommand"
        /// </summary>
        public GreaterPixelDelegate m_GreaterPixelDelegate = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="GreaterLambdaCommand"/> class.
        /// </summary>
        public GreaterLambdaCommand()
            : this(null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GreaterLambdaCommand"/> class.
        /// </summary>
        /// <param name="pixelDelegate">The pixel delegate.</param>
        public GreaterLambdaCommand(GreaterPixelDelegate pixelDelegate)
        {
            this.m_SupportedPixelFormats = new PixelFormat[] { PixelFormat.Format24bppRgb, PixelFormat.Format24bppRgb, PixelFormat.Format32bppPArgb };
            if (pixelDelegate == null)
            {
                throw new ArgumentNullException("pixelDelegate");
            }
            this.m_GreaterPixelDelegate = pixelDelegate;
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            Apply(_bitmap, m_GreaterPixelDelegate);
            return _bitmap;
        }

        /// <summary>
        /// Applies the specified bitmap.
        /// </summary>
        /// <param name="bitmap">The bitmap.</param>
        /// <param name="pixelDelegate">The pixel delegate.</param>
        public void Apply(UnsafeBitmap bitmap, GreaterPixelDelegate pixelDelegate)
        {
            if (pixelDelegate == null)
            {
                throw new ArgumentNullException("pd");
            }
            GreaterPixelDelegate oldDelegate = this.m_GreaterPixelDelegate;
            try
            {
                this.m_GreaterPixelDelegate = pixelDelegate;
                this.PerformActualCommand(bitmap);
            }
            finally
            {
                this.m_GreaterPixelDelegate = oldDelegate;
            }
        }

        //TODO: check if this can be deleted (inheritance)
        /// <summary>
        /// Performs the actual command.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        protected Image PerformActualCommand(UnsafeBitmap source)
        {
            return this.PerformActualCommand(source, new Rectangle(0, 0, source.Width - 1, source.Height - 1));
        }

        /// <summary>
        /// Performs the actual command.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="imageArea">The image area.</param>
        /// <returns></returns>
        protected Image PerformActualCommand(UnsafeBitmap _bitmap, Rectangle imageArea)
        {
            UnsafeBitmap bitmap = _bitmap;
            for (int y = imageArea.Top; y < imageArea.Height; y++)
            {
                for (int x = imageArea.Left; x < imageArea.Width; x++)
                {
                    Color sourceColor = bitmap.GetPixel(x, y);
                    Color destColor = this.m_GreaterPixelDelegate(new LambdaPixel(sourceColor, x, y, bitmap, imageArea));
                    bitmap.SetPixel(x, y, destColor);
                }
            }
            return bitmap.InternalBitmap;
        }

        /// <summary>
        /// Gets or sets PixelDelegate
        /// </summary>
        /// <value></value>
        public new GreaterPixelDelegate PixelDelegate
        {
            get
            {
                return this.m_GreaterPixelDelegate;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this.m_GreaterPixelDelegate = value;
            }
        }
    }
}